Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The possibility to specify a path to the settings file #41

Closed
wants to merge 97 commits into from
Closed

The possibility to specify a path to the settings file #41

wants to merge 97 commits into from

Conversation

kudashevs
Copy link
Contributor

@kudashevs kudashevs commented Feb 16, 2022

Hello again 👋,

This is a draft PR of the first step of a proposition to the laravel-ignition.

This is a new component FileConfigManager which is implemented through a new ConfigManager interface. The interface is a little bit over-engineered with the getSource method, however, I've found it useful for testing purposes and it could be useful in the future (but it could be removed, though). So, the new FileConfigManager gets all the responsibility to manage the settings file:

  • it accepts a path through the constructor and validates it
  • if the path is not provided it tries to find an appropriate path from the environment (was taken from DefaultConfigFinder)
  • it can load the options from a file
  • it can save the options to the file
  • it can create the file (and this seems the most important because DefaultConfigFinder didn't do that, so DefaultConfigFinderTest didn't work properly for me if I didn't have a created settings file)
  • it is covered with tests in some weak points

Copy link
Member

@AlexVanderbist AlexVanderbist left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, I've commented on a couple of nitpicks but nothing major! Thanks for taking the time to add proper tests as well. Looking forward to merging this one 👍


class FileConfigManager implements ConfigManager
{
private const SETTINGS_FILE_NAME = '.ignition.json';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can rename this to CONFIG_FILE_NAME to keep it in line with the ConfigManager, etc...

Suggested change
private const SETTINGS_FILE_NAME = '.ignition.json';
private const CONFIG_FILE_NAME = '.ignition.json';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,

I kind of agree, but to me, the config/ignition.php is a config file and .ignition.json is a settings file. One of the reasons for this separation is the Laravel Ignition button naming (we have a Save settings button there). So, not to confuse users I tried to differentiate these two concepts by introducing this term settings file. That's why I would like to stick to this name settings file and use it for this file if you don't mind.

However, if you don't like this differentiation at all let's change it. @AlexVanderbist please let me know about your decision.

src/Config/FileConfigManager.php Outdated Show resolved Hide resolved
src/Config/FileConfigManager.php Outdated Show resolved Hide resolved
return rtrim($path, DIRECTORY_SEPARATOR);
}

public function createSource(): bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSource might be a bit vague. Maybe we can rename it to something a bit more explicite?

Suggested change
public function createSource(): bool
public function createConfigFile(): bool

Copy link
Contributor Author

@kudashevs kudashevs Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree that the term source is vague. However, I tried to make the contract as abstract as possible (in case if in the future somebody is going to use a database or other persistent source to keep the settings). If there is no need for the abstraction let's rename it according to your final decision about the config or settings file above. But if there is a chance that the persistent source will have changed in the future, let's try to come up with a less vague definition for that (for example Storage).

@AlexVanderbist please let me know about your decision.

return rtrim($path, DIRECTORY_SEPARATOR);
}

public function createSource(): bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what do you think about calling this method from the save() method? We can still keep it public for use inside of tests tho.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea to introduce and make createSource() method public was to give the possibility to create a settings storage somewhere outside. For example, if I don't want to use the createSource every time on the saving operation, I can just use it in a ServiceProvider to create it once. So, I'm still thinking about how to implement it and you are absolutely right that it's better to remove this call from IgnitionConfig.php.

I need to think about a better solution on how to create storage once and not use it on every save() call. Until then, I'll move it to the save() method.

Comment on lines 37 to 41
if (! function_exists('app')) {
return new FileConfigManager();
}

return app(ConfigManager::class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting approach! :D

Copy link
Contributor Author

@kudashevs kudashevs Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly speaking, this approach is a little bit dangerous, because it leads to an exception if there is no bound instance in the container (according to PSR-11 and according to the Larave documentation). In my view, this is the case where fail fast looks better than fail soft.

} catch (Throwable) {
return false;
}
$this->manager->createSource();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this call be moved to inside of the $manager->save() method?

Comment on lines 7 to 14
/** @return array<string, mixed> */
public function load(): array;

/** @param array<string, mixed> $options */
public function save(array $options): bool;

/** @return array<string, mixed> */
public function getSource(): array;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think these doc block typehints add a lot (I know we've used them in other places as well and I should really go over those and clean up 😅)

Copy link
Contributor Author

@kudashevs kudashevs Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather leave them. At least, they show that they are expected to be associative arrays :)

tests/Config/FileConfigManagerTest.php Outdated Show resolved Hide resolved
@kudashevs
Copy link
Contributor Author

kudashevs commented Feb 20, 2022

@AlexVanderbist I tried to push it gently but without any luck. Sorry for that 😭 I should've made another PR from another branch, probably. I don't know how to cope with such situations when the only option is to push with force. What are your suggestions, btw?

So, this is a modified solution reworked by taking into account suggestions and some new ideas:

  • Maybe we can rename this to CONFIG_FILE_NAME to keep it in line with the ConfigManager, etc...
    Because I haven’t received any feedback on the explanations about my decision, I would like to stick to this naming for now.
  • For most OSS package we avoid private for all properties and functions
    I changed the visibility for all the methods which look worth being inherited.
  • Explicitly importing Throwable is more in line with Laravel's codebase
    Done for all the cases.
  • createSource might be a bit vague. Maybe we can rename it to something a bit more explicit?
    The interface of the ConfigManager was change to:
  - load() 
  - save()
  - createPersistent() // could be safely removed if it seems a good idea not to expose it to the outside world
  - getPersistentInfo()

, that looks better to me and more self-explantory

  • Also, what do you think about calling this method from the save() method?
    Done. The FileConfigManager uses a new flow. It creates a file at the initialization moment (createFile()) and retains two states ($path, $file) for the future use. That way it is not still necessary to create a persistent storage somewhere else (that's why createPersistent() method could be removed from the public Interface if it seems a good idea).
  • Interesting approach!
    The approach turned out a fig failure when I had tried to update laravel-ignition with this package. So, the solution was rethought and modified. Now, it should work without any possible issues.
  • Can this call be moved to inside of the $manager->save() method?
    Done. It was mentioned above.
  • I don't think these doc block typehints add a lot
    Because I haven’t received any feedback I left them as is.

Besides these refinements, I have finished a branch with the integration of these changes to the laravel-ignition. I haven't made a PR yet, because the branch uses a non-standard composer.json. Could you please give it a look?

As an afterthought, I would like to propose to extract the functionality based on user's home directory (everything under the initPathFromEnvironment()) to another class. It's not really crucial, but it is obviously sort of my fault, that I mixed them up. It seems like these (use predefined filename vs use the dynamically retrieved user home directory) are two different responsibilities with different functionality (works per project vs works for all the projects). So, it is better to do in the future.

@kudashevs
Copy link
Contributor Author

kudashevs commented Feb 26, 2022

I'd better close it.

@kudashevs kudashevs closed this Feb 26, 2022
@kudashevs kudashevs deleted the feature/specify_settings_file branch February 26, 2022 21:31
@AlexVanderbist
Copy link
Member

Hey @kudashevs, sorry about the delay. I didn't mean to come across as disrespectful or uninterested. If you would still like to see this PR merged, feel free to re-open it and I'll be happy to continue looking at it.

@kudashevs
Copy link
Contributor Author

kudashevs commented Mar 1, 2022

Hello @AlexVanderbist

No worries. I just thought that the proposition is not still interesting (because it turned out to be kind of messy, big, and complicated). Let's try it one more time. If you don't mind I'm going to open a new PR.

@AlexVanderbist
Copy link
Member

Awesome, thanks! I'll go over it later today 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants